<!DOCTYPE html>
<html lang="zh-CN">
  <head>
    <meta charset="utf-8" />
    <meta
      name="viewport"
      content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no, minimal-ui"
    />
    <title>Retrofit2学习笔记 | zzqhost</title>
    <meta name="description" content="天行健，君子以自强不息；地势坤，君子以厚德载物" />
    <meta property="og:type" content="website" />
    <meta property="og:title" content="Retrofit2学习笔记 | zzqhost" />
    <meta property="og:site_name" content="Retrofit2学习笔记 | zzqhost" />
    <meta property="og:locale" content="zh-CN" />
    <meta name="twitter:card" content="summary" />
    <meta name="twitter:title" content="Retrofit2学习笔记 | zzqhost" />
    <link rel="shortcut icon" href="/favicon.ico">
    
    <link rel="preload" href="/assets/css/0.styles.948dbb0a.css" as="style"><link rel="preload" href="/assets/js/app.3e01f5cb.js" as="script"><link rel="preload" href="/assets/js/1.21aaee9f.js" as="script"><link rel="preload" href="/assets/js/14.98a4de9c.js" as="script"><link rel="preload" href="/assets/js/5.352c1a43.js" as="script"><link rel="preload" href="/assets/js/7.4a8a313c.js" as="script"><link rel="preload" href="/assets/js/9.5ce2172b.js" as="script"><link rel="preload" href="/assets/js/6.8b8fad13.js" as="script"><link rel="preload" href="/assets/js/26.2b97bfde.js" as="script"><link rel="preload" href="/assets/js/13.186562af.js" as="script"><link rel="preload" href="/assets/js/15.740f4afc.js" as="script"><link rel="prefetch" href="/assets/js/10.e3f309c4.js"><link rel="prefetch" href="/assets/js/11.7bef5ef0.js"><link rel="prefetch" href="/assets/js/12.cf546b2f.js"><link rel="prefetch" href="/assets/js/16.c0f3e779.js"><link rel="prefetch" href="/assets/js/17.ee3f21b3.js"><link rel="prefetch" href="/assets/js/18.2c35035c.js"><link rel="prefetch" href="/assets/js/19.e4881cfc.js"><link rel="prefetch" href="/assets/js/20.95040517.js"><link rel="prefetch" href="/assets/js/21.cdbb212e.js"><link rel="prefetch" href="/assets/js/22.7d278bc3.js"><link rel="prefetch" href="/assets/js/23.1e2b813e.js"><link rel="prefetch" href="/assets/js/24.6cc55189.js"><link rel="prefetch" href="/assets/js/25.ea35ed40.js"><link rel="prefetch" href="/assets/js/27.d323aa74.js"><link rel="prefetch" href="/assets/js/28.30416d07.js"><link rel="prefetch" href="/assets/js/29.02b97357.js"><link rel="prefetch" href="/assets/js/30.95aedede.js"><link rel="prefetch" href="/assets/js/31.79b824fd.js"><link rel="prefetch" href="/assets/js/32.d0cd6341.js"><link rel="prefetch" href="/assets/js/33.14c3c5b9.js"><link rel="prefetch" href="/assets/js/34.ac56f38e.js"><link rel="prefetch" href="/assets/js/35.54820345.js"><link rel="prefetch" href="/assets/js/36.37013d97.js"><link rel="prefetch" href="/assets/js/37.38353206.js"><link rel="prefetch" href="/assets/js/38.36296a20.js"><link rel="prefetch" href="/assets/js/39.37df68d6.js"><link rel="prefetch" href="/assets/js/4.54d65165.js"><link rel="prefetch" href="/assets/js/40.ffbd7a88.js"><link rel="prefetch" href="/assets/js/41.5db561d2.js"><link rel="prefetch" href="/assets/js/42.d876627b.js"><link rel="prefetch" href="/assets/js/43.e5008459.js"><link rel="prefetch" href="/assets/js/44.a24dc4a2.js"><link rel="prefetch" href="/assets/js/45.f696c4e1.js"><link rel="prefetch" href="/assets/js/8.8c0e5954.js"><link rel="prefetch" href="/assets/js/vendors~search.c4563fd1.js">
    <link rel="stylesheet" href="/assets/css/0.styles.948dbb0a.css">
  </head>
  <body>
    <div id="loader-wrapper" style="display: none;opacity:0">
      <div id="loader"></div>
      <div class="loader-section section-left"></div>
      <div class="loader-section section-right"></div>
    </div>
    <div id="app" data-server-rendered="true"><div style="height:100%;" data-v-80d5f2bc><section class="el-container main-container" data-v-80d5f2bc><aside class="el-aside menu" style="width:auto;" data-v-67e96130 data-v-80d5f2bc><ul role="menubar" class="menu-wrap el-menu" style="background-color:;" data-v-67e96130><li data-v-67e96130><div class="brand-wrap" style="background-image:url(/brand.jpg);" data-v-67e96130><div class="brand" data-v-67e96130><a href="/" class="avatar waves-effect waves-circle waves-light router-link-active" data-v-67e96130><img src="/avatar.jpg" data-v-67e96130></a> <hgroup class="introduce" data-v-67e96130><div class="nickname" data-v-67e96130>zzqhost</div> <a title="zzqhost@163.com" class="mail" data-v-67e96130>zzqhost@163.com</a></hgroup></div></div></li> <li role="menuitem" tabindex="-1" class="el-menu-item" style="padding-left:20px;color:;background-color:;" data-v-67e96130><i class="iconfont icon-home" data-v-67e96130></i> <span class="item-title" data-v-67e96130>主页</span></li> <li role="menuitem" tabindex="-1" class="el-menu-item" style="padding-left:20px;color:;background-color:;" data-v-67e96130><i class="iconfont icon-biaoqian" data-v-67e96130></i> <span class="item-title" data-v-67e96130>标签分类</span></li> <li role="menuitem" tabindex="-1" class="el-menu-item" style="padding-left:20px;color:;background-color:;" data-v-67e96130><i class="iconfont icon-wenzhang" data-v-67e96130></i> <span class="item-title" data-v-67e96130>时间归档</span></li> <!----> <li role="menuitem" tabindex="-1" class="el-menu-item" style="padding-left:20px;color:;background-color:;" data-v-67e96130><i class="iconfont icon-aboutme" data-v-67e96130></i> <span class="item-title" data-v-67e96130>自我介绍</span></li></ul></aside> <section class="el-container container-warp" data-v-80d5f2bc><header id="topHeader" class="el-header top-header" style="height:60px;padding-left:260px;" data-v-1a942948 data-v-80d5f2bc><div class="header-warp el-row is-align-middle el-row--flex" data-v-1a942948><div class="el-col el-col-12 el-col-xs-7" data-v-1a942948><div class="el-row is-align-middle el-row--flex" data-v-1a942948><div class="el-col el-col-2" data-v-1a942948><button type="button" class="el-button el-button--primary is-circle" data-v-1a942948><!----><!----><span><i class="iconfont icon-caidan" data-v-1a942948></i></span></button></div></div></div> <div class="el-col el-col-20 el-col-xs-24" data-v-1a942948><div class="grid-content bg-purple-light" data-v-1a942948><div class="el-row is-justify-end is-align-middle el-row--flex" data-v-1a942948><div class="el-col el-col-13 el-col-xs-24 el-col-sm-21 el-col-md-17 el-col-lg-13" data-v-1a942948><div aria-haspopup="listbox" role="combobox" aria-owns="el-autocomplete-3491" class="el-autocomplete search-input" data-v-1a942948><div class="el-input el-input--small el-input--suffix"><!----><input type="text" autocomplete="off" valueKey="value" popperClass="search-popper" placeholder="搜搜看" fetchSuggestions="function () { [native code] }" debounce="300" placement="bottom-start" popperAppendToBody="true" value="" class="el-input__inner"><!----><span class="el-input__suffix"><span class="el-input__suffix-inner"><i class="el-input__icon el-icon-search search-ico" data-v-1a942948></i><!----></span><!----></span><!----></div><div role="region" class="el-autocomplete-suggestion el-popper search-popper" style="width:;display:none;"><div class="el-scrollbar"><div class="el-autocomplete-suggestion__wrap el-scrollbar__wrap el-scrollbar__wrap--hidden-default"><ul class="el-scrollbar__view el-autocomplete-suggestion__list"></ul></div><div class="el-scrollbar__bar is-horizontal"><div class="el-scrollbar__thumb" style="width:0;transform:translateX(0%);ms-transform:translateX(0%);webkit-transform:translateX(0%);"></div></div><div class="el-scrollbar__bar is-vertical"><div class="el-scrollbar__thumb" style="height:0;transform:translateY(0%);ms-transform:translateY(0%);webkit-transform:translateY(0%);"></div></div></div></div></div></div></div></div></div></div></header> <main class="el-main my-main" style="margin-left:240px;" data-v-105de776 data-v-80d5f2bc><div class="content-header index-header" data-v-60d87e45 data-v-105de776><div class="container fade-scale in" data-v-60d87e45><h1 id="conentHeader" class="title" data-v-60d87e45>Retrofit2学习笔记</h1> <h5 class="subtitle" data-v-60d87e45>最后更新时间：2019-07-04 18:08:36</h5></div></div> <div data-v-95d4b5b2 data-v-105de776 data-v-105de776><div class="post-content el-row is-justify-center el-row--flex" data-v-95d4b5b2><div id="post-card" class="post-card post-sign el-col el-col-16 el-col-xs-24 el-col-sm-23 el-col-md-23 el-col-lg-16" data-v-95d4b5b2><div class="content__default" data-v-95d4b5b2><p>时至今日，Android的网络框架不再像之前那么到处都是，随着Google把HttpClient直接删掉，似乎意味着Android越来越成熟。网络框架中的佼佼者Volley也不再那么光鲜，取而代之的是Retrofit和okHttp。 这两个网络库都是Square这个牛逼的公司出品的,这个公司出品了好多开源库, 大家有兴趣可以去了解下.</p> <p>作为一个资深的Android从业者(呵呵~), 一直没有好好研究过retrofit, 这次下定决心要好好研究一下包括Retrofit + okHttp + RxJava等一系列新技术, 免得被时代抛弃.</p> <h1 id="前言"><a href="#前言" aria-hidden="true" class="header-anchor">#</a> 前言</h1> <p>如果看Retrofit的源码会发现其实质上就是对okHttp的封装，使用面向接口的方式进行网络请求，利用动态生成的代理类封装了网络接口请求的底层, 其将请求返回javaBean. 它非常适合于restful url格式的请求，使用更多的注解方式提供各种功能.</p> <h2 id="restful"><a href="#restful" aria-hidden="true" class="header-anchor">#</a> Restful</h2> <p>Retrofit 把REST API返回的数据转化为Java对象，就像ORM框架那样，把数据库内的存储的数据转化为相应的Java bean对象。
那么我们知道Retrofit是一个类型安全的网络框架，而且它是使用REST API的，接下来我们看看什么是REST吧。</p> <ul><li><strong>Resources Representational State Transfer</strong></li> <li>翻译过来就是<strong>资源表现层状态转化</strong></li> <li>具体请参考我的博客{% post_link 理解RESTful架构 %}</li> <li>更多关于REST的介绍：<a href="https://github.com/astaxie/build-web-application-with-golang/blob/master/zh/08.3.md" target="_blank" rel="noopener noreferrer">什么是REST - GitHub<svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg></a></li></ul> <h1 id="以一个简单的例子来入门"><a href="#以一个简单的例子来入门" aria-hidden="true" class="header-anchor">#</a> 以一个简单的例子来入门</h1> <h2 id="引入retrofit库"><a href="#引入retrofit库" aria-hidden="true" class="header-anchor">#</a> 引入Retrofit库</h2> <ul><li><p>首先，在gralde文件中引入后续要用到的库。(以下是我参考的其它博文中的,其中的版本可能有点老,先不管那么多了,能跑起来再说, 等我试验完后把它们更新成最新的版本)
compile 'com.squareup.retrofit:retrofit:2.0.0-beta2'
compile 'com.squareup.retrofit:converter-gson:2.0.0-beta2'
compile 'com.squareup.retrofit:adapter-rxjava:2.0.0-beta2'</p> <pre><code>  compile 'com.squareup.okhttp:okhttp:2.4.0'

  compile 'io.reactivex:rxjava:1.0.14'
  compile 'io.reactivex:rxandroid:1.0.1'
</code></pre></li></ul> <p>接下来我们写一个例子,并一步步进行分析。</p> <h2 id="小例子"><a href="#小例子" aria-hidden="true" class="header-anchor">#</a> 小例子</h2> <ul><li><p>创建两个类: 实体Bean和服务接口类
public static class Contributor {
public final String login;
public final int contributions;
public Contributor(String login, int contributions) {
this.login = login;
this.contributions = contributions;
}
@Override
public String toString() {
return &quot;Contributor{&quot; +
&quot;login='&quot; + login + ''' +
&quot;, contributions=&quot; + contributions +
'}';
}
}</p> <pre><code>  public interface GitHub {
      @GET(&quot;/repos/{owner}/{repo}/contributors&quot;)
      Call&lt;List&lt;Contributor&gt;&gt; contributors(
          @Path(&quot;owner&quot;) String owner,
          @Path(&quot;repo&quot;) String repo);
  }
</code></pre></li> <li><p>接下来创建Retrofit2的实例，并设置BaseUrl和Gson转换。
Retrofit retrofit = new Retrofit.Builder()
.baseUrl(&quot;https://api.github.com&quot;)
.addConverterFactory(GsonConverterFactory.create())
.client(new OkHttpClient())
.build();</p></li> <li><p>创建请求服务，并为网络请求方法设置参数
GitHub gitHubService = retrofit.create(GitHub.class);
Call&lt;List<Contributor>&gt; call = gitHubService.contributors(&quot;square&quot;, &quot;retrofit&quot;);</Contributor></p></li> <li><p>最后，请求网络，并获取响应
try{
Response&lt;List<Contributor>&gt; response = call.execute(); // 同步
Log.d(TAG, &quot;response:&quot; + response.body().toString());
} catch (IOException e) {
e.printStackTrace();
}</Contributor></p></li> <li><p><strong>Call是Retrofit中重要的一个概念，代表被封装成单个请求/响应的交互行为</strong></p> <ul><li>通过调用Retrofit2的execute（<strong>同步</strong>）或者enqueue（<strong>异步</strong>）方法，发送请求到网络服务器，并返回一个响应（Response）。</li> <li>它具有如下特点
<ul><li>独立的请求和响应模块</li> <li>从响应处理分离出请求创建</li> <li>每个实例只能使用一次。</li> <li>Call可以被克隆。</li> <li>支持同步和异步方法。</li> <li>能够被取消。</li></ul></li></ul></li> <li><p>由于call只能被执行一次，所以按照上面的顺序再次执行Call将会得到如下错误。
java.lang.IllegalStateException: Already executed</p></li> <li><p>我们可以通过clone，来克隆一份call，从而可以重新调用一次这个接口
// clone
Call&lt;List<Contributor>&gt; call1 = call.clone();
// 5. 请求网络，异步
call1.enqueue(new Callback&lt;List<Contributor>&gt;() {
@Override
public void onResponse(Response&lt;List<Contributor>&gt; response, Retrofit retrofit) {
Log.d(TAG, &quot;response:&quot; + response.body().toString());
}</Contributor></Contributor></Contributor></p> <pre><code>      @Override
      public void onFailure(Throwable t) {

      }
  });
</code></pre></li></ul> <h2 id="总结"><a href="#总结" aria-hidden="true" class="header-anchor">#</a> 总结</h2> <p>下面我们总结一下使用retrofit的基本步骤</p> <ol><li>定义网络请求的实体bean和服务接口类</li> <li>创建retrofit2的实例
<ul><li>在这里需要设置baseUrl</li> <li>设置一个OkHttpClient类的实例,可以是默认的,也可以是定制的,如果有需要可以整体app使用一个单例实例. 有空再单独说一下这个事.</li> <li>设置Gson等转换器</li></ul></li> <li>创建请求服务代理类, 并为网络请求方法设置参数,生成一个Call对象</li> <li>请求网络, 并获取响应
<ul><li>支持execute（同步）和 enqueue（异步）</li> <li>Call只能执行一次</li> <li>能够被取消</li></ul></li></ol> <h1 id="retrofit-用法"><a href="#retrofit-用法" aria-hidden="true" class="header-anchor">#</a> retrofit 用法</h1> <h2 id="服务接口类"><a href="#服务接口类" aria-hidden="true" class="header-anchor">#</a> 服务接口类</h2> <p>Retrofit需要注解接口的请求方法和方法的参数来表明该请求需要怎么样的处理。</p> <h3 id="请求方法"><a href="#请求方法" aria-hidden="true" class="header-anchor">#</a> 请求方法</h3> <ul><li>每一个方法必须要有一个HTTP注解来标明请求的方式和相对URL。有五种内置的注解方式：GET、POST、PUT、DELETE以及HEAD。资源的相对URL需要在注解里面明确给出：
@GET(&quot;users/list&quot;)</li> <li>当然作为特殊用法: 你也可以将query参数直接写死在URL里
@GET(&quot;users/list?sort=desc&quot;)</li></ul> <h3 id="url操作"><a href="#url操作" aria-hidden="true" class="header-anchor">#</a> URL操作</h3> <p>包括路径的替换, 参数的替换, 请求头参数, post请求, 表单等</p> <h4 id="路径替换和参数"><a href="#路径替换和参数" aria-hidden="true" class="header-anchor">#</a> 路径替换和参数</h4> <ol><li><p>路径替换
interface SomeService {
@GET(&quot;/some/endpoint/{thing}&quot;)
Call<SomeResponse> someEndpoint(
@Path(&quot;thing&quot;) String thing);
}</SomeResponse></p> <pre><code> someService.someEndpoint(&quot;bar&quot;);

 // GET /some/endpoint/bar HTTP/1.1
</code></pre></li> <li><p>固定查询参数
// 服务
interface SomeService {
@GET(&quot;/some/endpoint?fixed=query&quot;)
Call<SomeResponse> someEndpoint();
}</SomeResponse></p> <pre><code> // 方法调用
 someService.someEndpoint();

 // 请求头
 // GET /some/endpoint?fixed=query HTTP/1.1
</code></pre></li> <li><p>动态参数
// 服务
interface SomeService {
@GET(&quot;/some/endpoint&quot;)
Call<SomeResponse> someEndpoint(
@Query(&quot;dynamic&quot;) String dynamic);
}</SomeResponse></p> <pre><code> // 方法调用
 someService.someEndpoint(&quot;query&quot;);

 // 请求头
 // GET /some/endpoint?dynamic=query HTTP/1.1
</code></pre></li> <li><p>动态参数（Map）
// 服务
interface SomeService {
@GET(&quot;/some/endpoint&quot;)
Call<SomeResponse> someEndpoint(
@QueryMap Map&lt;String, String&gt; dynamic);
}</SomeResponse></p> <pre><code> // 方法调用
 someService.someEndpoint(
  Collections.singletonMap(&quot;dynamic&quot;, &quot;query&quot;));
 // 请求头
 // GET /some/endpoint?dynamic=query HTTP/1.1
</code></pre></li> <li><p>省略动态参数
interface SomeService {
@GET(&quot;/some/endpoint&quot;)
Call<SomeResponse> someEndpoint(
@Query(&quot;dynamic&quot;) String dynamic);
}</SomeResponse></p> <pre><code> // 方法调用
 someService.someEndpoint(null);

 // 请求头
 // GET /some/endpoint HTTP/1.1
</code></pre></li> <li><p>固定+动态参数
interface SomeService {
@GET(&quot;/some/endpoint?fixed=query&quot;)
Call<SomeResponse> someEndpoint(
@Query(&quot;dynamic&quot;) String dynamic);
}</SomeResponse></p> <pre><code> // 方法调用
 someService.someEndpoint(&quot;query&quot;);

 // 请求头
 // GET /some/endpoint?fixed=query&amp;dynamic=query HTTP/1.1
</code></pre></li></ol> <h4 id="请求头"><a href="#请求头" aria-hidden="true" class="header-anchor">#</a> 请求头</h4> <ol><li><p>固定头
interface SomeService {
@GET(&quot;/some/endpoint&quot;)
@Headers(&quot;Accept-Encoding: application/json&quot;)
Call<SomeResponse> someEndpoint();
}</SomeResponse></p> <pre><code> someService.someEndpoint();

 // GET /some/endpoint HTTP/1.1
 // Accept-Encoding: application/json
</code></pre></li> <li><p>动态头
interface SomeService {
@GET(&quot;/some/endpoint&quot;)
Call<SomeResponse> someEndpoint(
@Header(&quot;Location&quot;) String location);
}</SomeResponse></p> <pre><code> someService.someEndpoint(&quot;Droidcon NYC 2015&quot;);

 // GET /some/endpoint HTTP/1.1
 // Location: Droidcon NYC 2015
</code></pre></li> <li><p>固定+动态头
interface SomeService {
@GET(&quot;/some/endpoint&quot;)
@Headers(&quot;Accept-Encoding: application/json&quot;)
Call<SomeResponse> someEndpoint(
@Header(&quot;Location&quot;) String location);
}</SomeResponse></p> <pre><code> someService.someEndpoint(&quot;Droidcon NYC 2015&quot;);

 // GET /some/endpoint HTTP/1.1
 // Accept-Encoding: application/json
 // Location: Droidcon NYC 2015
</code></pre></li></ol> <h4 id="post和put请求"><a href="#post和put请求" aria-hidden="true" class="header-anchor">#</a> post和put请求</h4> <ol><li><p>Post请求，无Body
interface SomeService {
@POST(&quot;/some/endpoint&quot;)
Call<SomeResponse> someEndpoint();
}</SomeResponse></p> <pre><code> someService.someEndpoint();

 // POST /some/endpoint?fixed=query HTTP/1.1
 // Content-Length: 0
</code></pre></li> <li><p>Post请求有Body
interface SomeService {
@POST(&quot;/some/endpoint&quot;)
Call<SomeResponse> someEndpoint(
@Body SomeRequest body);
}</SomeResponse></p> <pre><code> someService.someEndpoint();

 // POST /some/endpoint HTTP/1.1
 // Content-Length: 3
 // Content-Type: greeting
 //
 // Hi!
</code></pre></li> <li><p>表单编码字段
interface SomeService {
@FormUrlEncoded
@POST(&quot;/some/endpoint&quot;)
Call<SomeResponse> someEndpoint(
@Field(&quot;name1&quot;) String name1,
@Field(&quot;name2&quot;) String name2);
}</SomeResponse></p> <pre><code> someService.someEndpoint(&quot;value1&quot;, &quot;value2&quot;);

 // POST /some/endpoint HTTP/1.1
 // Content-Length: 25
 // Content-Type: application/x-www-form-urlencoded
 //
 // name1=value1&amp;name2=value2
</code></pre></li> <li><p>表单编码字段（Map）
interface SomeService {
@FormUrlEncoded
@POST(&quot;/some/endpoint&quot;)
Call<SomeResponse> someEndpoint(
@FieldMap Map&lt;String, String&gt; names);
}</SomeResponse></p> <pre><code> someService.someEndpoint(
  // ImmutableMap是OKHttp中的工具类
  ImmutableMap.of(&quot;name1&quot;, &quot;value1&quot;, &quot;name2&quot;, &quot;value2&quot;));

 // POST /some/endpoint HTTP/1.1
 // Content-Length: 25
 // Content-Type: application/x-www-form-urlencoded
 //
 // name1=value1&amp;name2=value2
</code></pre></li> <li><p>可以通过**@Multipart注解方法**
来发送Mutipart请求。每个部分需要使用@Part来注解。
@Multipart
@PUT(&quot;user/photo&quot;)
Call<User> updateUser(@Part(&quot;photo&quot;) RequestBody photo, @Part(&quot;description&quot;) RequestBody description);</User></p> <pre><code> // 多个请求部分需要使用Retrofit的converter或者是自己实现 RequestBody来处理自己内部的数据序列化。
</code></pre></li></ol> <h2 id="上传和下载"><a href="#上传和下载" aria-hidden="true" class="header-anchor">#</a> 上传和下载</h2> <ul><li>这几个未深入的学习, 着急学习的同学可以参考<a href="http://blog.csdn.net/lmj623565791/article/details/51304204" target="_blank" rel="noopener noreferrer">Retrofit2 完全解析 探索与okhttp之间的关系<svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg></a></li></ul> <h3 id="单文件上传-multipart"><a href="#单文件上传-multipart" aria-hidden="true" class="header-anchor">#</a> 单文件上传@Multipart</h3> <h3 id="多文件上传-partmap"><a href="#多文件上传-partmap" aria-hidden="true" class="header-anchor">#</a> 多文件上传@PartMap</h3> <h3 id="下载文件"><a href="#下载文件" aria-hidden="true" class="header-anchor">#</a> 下载文件</h3> <ul><li>这个其实我觉得直接使用okhttp就好了，使用retrofit去做这个事情真的有点瞎用的感觉~~</li> <li>...</li></ul> <h2 id="retrofit配置"><a href="#retrofit配置" aria-hidden="true" class="header-anchor">#</a> Retrofit配置</h2> <p>Retrofit类会通过你定义的API接口转化为可调用的对象。默认情况下，Retrofit会返还给你合理的默认值，但也允许你进行指定。</p> <h3 id="转化器（converters）"><a href="#转化器（converters）" aria-hidden="true" class="header-anchor">#</a> 转化器（Converters）</h3> <ul><li><p>默认情况下，Retrofit只能将HTTP体反序列化为OKHttp的 ResonseBody 类型，而且只能接收 RequestBody类型作为 @Body。</p></li> <li><p>转化器的加入可以用于支持其他的类型。以下六个同级模块采用了常用的序列化库来为你提供方便。
Gson: com.squareup.retrofit2:converter-gson
Jackson: com.squareup.retrofit2:converter-jackson
Moshi: com.squareup.retrofit2:converter-moshi
Protobuf: com.squareup.retrofit2:converter-protobuf
Wire: com.squareup.retrofit2:converter-wire
Simple XML: com.squareup.retrofit2:converter-simplexml
Scalars (primitives, boxed, and String): com.squareup.retrofit2:converter-scalars</p></li> <li><p>下面提供一个使用GsonConverterFactory类生成 GitHubService的接口实现gson反序列化的例子。
Retrofit retrofit = new Retrofit.Builder()
.baseUrl(&quot;https://api.github.com&quot;)
.addConverterFactory(GsonConverterFactory.create())
.build();</p> <pre><code>  GitHubService service = retrofit.create(GitHubService.class);
</code></pre></li> <li><p>自定义转化器</p> <ul><li>如果你需要与没有使用Retrofit提供的内容格式的API进行交互的话或者是你希望使用一个不同的库来实现现有的格式，你也可以轻松创建使用自己的转化器。</li> <li>你需要创建一个继承自Converter.Factory的类并且在构建适配器的时候加入到实例里面。</li></ul></li></ul> <h3 id="可插拔的执行机制-multiple-pluggable-execution-mechanisms"><a href="#可插拔的执行机制-multiple-pluggable-execution-mechanisms" aria-hidden="true" class="header-anchor">#</a> 可插拔的执行机制(Multiple, pluggable execution mechanisms)</h3> <pre><code>    interface GitHubService {
     @GET(&quot;/repos/{owner}/{repo}/contributors&quot;)
     // Call 代表的是CallBack回调机制
     Call&lt;List&lt;Contributor&gt;&gt; repoContributors(
         @Path(&quot;owner&quot;) String owner,
         @Path(&quot;repo&quot;) String repo);

     @GET(&quot;/repos/{owner}/{repo}/contributors&quot;)
     // Observable 代表的是RxJava的执行
     Observable&lt;List&lt;Contributor&gt;&gt; repoContributors2(
         @Path(&quot;owner&quot;) String owner,
         @Path(&quot;repo&quot;) String repo);

     @GET(&quot;/repos/{owner}/{repo}/contributors&quot;)
     Future&lt;List&lt;Contributor&gt;&gt; repoContributors3(
         @Path(&quot;owner&quot;) String owner,
         @Path(&quot;repo&quot;) String repo);
    }
</code></pre> <ul><li>注意，要在构建Retrofit时指定适配器模式为RxJavaCallAdapterFactory
Retrofit retrofit = new Retrofit.Builder()
.addConverterFactory(GsonConverterFactory.create())
.addCallAdapterFactory(RxJavaCallAdapterFactory.create())
.baseUrl(&quot;http://www.duitang.com&quot;)
.build();</li> <li>否则，会报出如下错误：
Caused by: java.lang.IllegalArgumentException: Could not locate call adapter for rx.Observable&lt;com.bzh.sampleretrofit.ClubBean&gt;. Tried:
* retrofit.ExecutorCallAdapterFactory</li></ul> <h3 id="配置okhttpclient"><a href="#配置okhttpclient" aria-hidden="true" class="header-anchor">#</a> 配置OkHttpClient</h3> <ul><li>这个需要简单提一下，很多时候，比如你使用retrofit需要统一的log管理，给每个请求添加统一的header等，这些都应该通过okhttpclient去操作，比如addInterceptor</li> <li>例如：
OkHttpClient client = new OkHttpClient.Builder().addInterceptor(new Interceptor()//log，统一的header等
{
@Override
public okhttp3.Response intercept(Chain chain) throws IOException
{
return null;
}
}).build();</li> <li>或许你需要更多的配置，你可以单独写一个OkhttpClient的单例生成类，在这个里面完成你所需的所有的配置，然后将OkhttpClient实例通过方法公布出来，设置给retrofit。</li> <li>设置方式：
Retrofit retrofit = new Retrofit.Builder()
.callFactory(OkHttpUtils.getClient())
.build();</li> <li>callFactory方法接受一个okhttp3.Call.Factory对象，OkHttpClient即为此Factory类的一个实现类</li></ul> <h2 id="混淆"><a href="#混淆" aria-hidden="true" class="header-anchor">#</a> 混淆</h2> <p>如果你的工程中使用了代码混淆，那么你的配置中需要添加一下的几行
-dontwarn retrofit2.**
-keep class retrofit2.** { *; }
-keepattributes Signature
-keepattributes Exceptions</p> <h1 id="retrofit2结构"><a href="#retrofit2结构" aria-hidden="true" class="header-anchor">#</a> Retrofit2结构</h1> <ul><li>Retrofit作为一个上层框架，自然有很多底层lib库支持，okio和okhttp都包含其中。
<img src="/images/Retrofit2%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0_1" alt="1"></li></ul> <h1 id="retrofit执行模式"><a href="#retrofit执行模式" aria-hidden="true" class="header-anchor">#</a> Retrofit执行模式</h1> <ul><li><img src="/images/Retrofit2%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0_2" alt="2"></li> <li><img src="/images/Retrofit2%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0_3" alt="3"></li> <li><img src="/images/Retrofit2%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0_4" alt="4"></li> <li><img src="/images/Retrofit2%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0_5" alt="5"></li></ul> <h1 id="参考"><a href="#参考" aria-hidden="true" class="header-anchor">#</a> 参考</h1> <p><a href="http://blog.csdn.net/lmj623565791/article/details/51304204" target="_blank" rel="noopener noreferrer">Retrofit2 完全解析 探索与okhttp之间的关系<svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg></a> <a href="http://www.jianshu.com/p/3e13e5d34531" target="_blank" rel="noopener noreferrer">Retrofit2.0使用总结<svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg></a> <a href="http://blog.csdn.net/biezhihua/article/details/49232289" target="_blank" rel="noopener noreferrer">好用的网络请求库Retrofit2（入门及讲解）<svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg></a> <a href="http://www.jianshu.com/p/442a29da7b23" target="_blank" rel="noopener noreferrer">Retrofit 2.0非常简单的入门（翻译官方文档）<svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg></a></p></div> <span id="footerPost" data-v-95d4b5b2></span></div> <div id="post-toc" class="post-toc el-col el-col-6" data-v-95d4b5b2><h4 class="catalog-title" data-v-95d4b5b2>TOC</h4> <div class="catalog-body" data-v-95d4b5b2><ul id="catalog-list" class="catalog-list" data-v-95d4b5b2></ul></div></div></div> <div class="post-nav el-row is-justify-space-around el-row--flex" data-v-95d4b5b2><div class="post-prev el-col el-col-7" data-v-95d4b5b2><div data-v-95d4b5b2><a href="/posts/%E5%AD%97%E7%AC%A6%E7%BC%96%E7%A0%81.html" data-v-95d4b5b2><i class="el-icon-arrow-left" data-v-95d4b5b2></i> Prev
        </a> <p class="nav-title" data-v-95d4b5b2>字符编码</p></div></div> <div class="post-next el-col el-col-7 el-col-lg-pull-5" data-v-95d4b5b2><div data-v-95d4b5b2><a href="/posts/Android%E6%89%93%E6%B8%A0%E9%81%93%E5%8C%85%E6%96%B9%E6%A1%88%E6%80%BB%E7%BB%93.html" data-v-95d4b5b2>
          Next
          <i class="el-icon-arrow-right" data-v-95d4b5b2></i></a> <p class="nav-title" data-v-95d4b5b2>Android打渠道包方案总结</p></div></div></div> <div class="el-row is-justify-center el-row--flex" data-v-95d4b5b2></div> <span data-v-d999c3f2 data-v-95d4b5b2><button type="button" class="el-button toc-btn el-button--primary is-circle" data-v-d999c3f2><!----><!----><span><i class="iconfont icon-service-directory" data-v-d999c3f2></i></span></button> <button type="button" class="el-button gotop-btn el-button--primary is-circle" data-v-d999c3f2><!----><!----><span><i class="el-icon-arrow-up" data-v-d999c3f2></i></span></button></span></div></main></section> <button type="button" class="el-button gotop-btn el-button--primary is-circle" style="display:none;" data-v-78a2dcfa data-v-80d5f2bc><!----><!----><span><i class="el-icon-arrow-up" data-v-78a2dcfa></i></span></button></section> <footer class="el-footer container-footer" style="height:60px;" data-v-76c50ee3 data-v-80d5f2bc><div class="footer-warp el-row is-justify-center is-align-center el-row--flex footerMargin" data-v-76c50ee3><div class="footer-top el-col el-col-24" data-v-76c50ee3><p class="ellipsis" data-v-76c50ee3><span data-v-76c50ee3>
          博客内容遵循
          <a rel="license" href="https://creativecommons.org/licenses/by-nc-sa/4.0/deed.zh" data-v-76c50ee3>知识共享 署名 - 非商业性 - 相同方式共享 4.0 国际协议</a></span></p></div> <div class="footer-bottom el-col el-col-24" data-v-76c50ee3><p class="ellipsis" data-v-76c50ee3><span data-v-76c50ee3><span data-v-76c50ee3>
            张志强的博客 © 2017-01 ~ 2021-03
          </span></span> <span data-v-76c50ee3>
          Power by
          <a href="https://vuepress.vuejs.org/zh/" target="_blank" data-v-76c50ee3>VuePress</a> Theme
          <a href="https://github.com/zhhlwd/vuepress-theme-indigo-material" target="_blank" data-v-76c50ee3>indigo material</a></span></p></div></div></footer> <div class="overlay" data-v-80d5f2bc></div></div><div class="global-ui"></div></div>
    <script src="/assets/js/app.3e01f5cb.js" defer></script><script src="/assets/js/1.21aaee9f.js" defer></script><script src="/assets/js/14.98a4de9c.js" defer></script><script src="/assets/js/5.352c1a43.js" defer></script><script src="/assets/js/7.4a8a313c.js" defer></script><script src="/assets/js/9.5ce2172b.js" defer></script><script src="/assets/js/6.8b8fad13.js" defer></script><script src="/assets/js/26.2b97bfde.js" defer></script><script src="/assets/js/13.186562af.js" defer></script><script src="/assets/js/15.740f4afc.js" defer></script>
  </body>
</html>
